#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <sys/types.h>
#include <dirent.h>

using namespace std;

typedef struct{
	char *nombre;
	int longitud;
	int documento;
	int posicion;

	} termino;

typedef struct{
	char *nombre;
	int longitud;
	int documento;
	int *posiciones;
	int cantPosiciones;

	} terminoAgrupado;

typedef struct {
	char *nombre;
	int id;
	char *directorio;
	} documento;

FILE* AbrirArchivo( const char *unNombre ){
  FILE *handle;
  char rta;
  char *nombreArchivo;
  int abierto = 0;
  char otroNombre[20];
  handle = fopen(unNombre,"r");
  if ( handle != 0 )
  {
	abierto = 1;
    //printf("fopen success! \n");
  }
  else {
	cout<<"Archivo inexistente. Desea probar otro archivo? [Y/N]: ";
    cin>> rta;
    while (rta != 'Y' && rta != 'y' && rta != 'N' && rta != 'n'){
    	cout<<"CARACTER INVALIDO. Desea probar otro archivo? [Y/N]: ";
    	cin>> rta;
    }
    if (rta == 'Y' || rta == 'y') {
    	printf ("Ingrese nombre de archivo: ");
        scanf("%s",otroNombre);
        nombreArchivo = (char*)malloc(sizeof(otroNombre));
        nombreArchivo = otroNombre;
        AbrirArchivo(nombreArchivo);
    }
    if (rta == 'N' || rta == 'n') {
    	if (abierto == 1) fclose(handle);
       	return handle;
    }
   }
   return handle;
}


int LeerTermino(FILE *unArchivo, char *unTermino, int *caracteres){

	// unArchivo tiene que ser un archivo ya abierto y listo para usar.
	// unTermino ya tiene que tener reservado el espacio en memoria para almacenar
	// el siguiente termino

	char letra;
	char unaPalabra[40];
	int pos = 0;
	*caracteres = 0;

	while ((letra = fgetc(unArchivo)) != EOF){
			if (letra == ' ' || letra == '\n'){
				if (pos != 0){
					for (int i = 0; i < strlen(unaPalabra); i++){
						*(unTermino + i) = unaPalabra[i];
					}
				return 0;
				}
			}
			if (letra == '.' || letra == ',' || letra == '?' || letra == '!' || letra == ';' || letra == ':' || letra == '"'){
				if (pos != 0){
					for (int i = 0; i < strlen(unaPalabra); i++){
							*(unTermino + i) = unaPalabra[i];
					}
					return 0;
				}
			}

			if (letra != ' '&& letra != '.' && letra != ',' && letra != '?' && letra != '!' && letra != '\n' && letra != '-' && letra != ';' && letra != ':' && letra != '"'){
				unaPalabra[pos]= letra;
				pos++;
				(*caracteres)++;
				}
		}
	return 1;
	}

int minusculas(char *palabra){
    while(*palabra != '\0'){
        if(*palabra >= 'A' && *palabra <= 'Z')
            *palabra += (char)32;
        palabra++;
    }
    return 0;
}


int contarTerminos(FILE *unArchivo){

	int cantidad = 0;
	char *unTermino;
	unTermino = (char*)malloc(20*sizeof(char));
	int i;

	while (LeerTermino(unArchivo, unTermino, &i) != 1){
		cantidad++;
	}
	rewind(unArchivo);
	free(unTermino);
	return cantidad;
}

int imprimirTermino(termino unTermino){

	char *unNombre;
	cout<<"TERMINO con minusculas: ";
	for (int i = 0; i < unTermino.longitud; i++){
		unNombre = unTermino.nombre;
		cout<<*((unTermino.nombre)+i);
	}
	cout<<endl;
	cout<<"POSICION: "<<unTermino.posicion<<endl;
	cout<<"LONGITUD: "<<unTermino.longitud<<endl;
	cout<<"DOCUMENTO: "<<unTermino.documento<<endl;
	cout<<endl;

	return 0;
}

int leerArchivo(FILE *unArchivo, termino *terminos, int id, int *pos){

	/*id le asigna un numero de identificacion al archivo que se lee*/

	cout<<"ENTRA EN LEERARCHIVO!!!!! "<<endl;

	int posicion = 1;
	int *unaLongitud;

	unaLongitud = (int*)malloc(sizeof(int));

	int cantTerminos = contarTerminos(unArchivo);
	cout<<"conto terminos del archivo: "<<cantTerminos<<endl;

	for (int i = 0; i < cantTerminos; i++){
		char caracteres[25];

		LeerTermino(unArchivo, (*(terminos+i+(*pos))).nombre , unaLongitud);
		minusculas((*(terminos+i+(*pos))).nombre);
		(*(terminos+i+(*pos))).longitud = *unaLongitud;
		(*(terminos+i+(*pos))).posicion = posicion;
		(*(terminos+i+(*pos))).documento = id;
		posicion++;
		cout<<"numero de termino del archivo: "<<i<<endl;
		imprimirTermino(*(terminos+i+(*pos)));

	}

	*pos = (*pos)+posicion-1;
	return 0;
}


int imprimirTerminoAgrupado(terminoAgrupado unTermino){

	char *unNombre;
	cout<<"TERMINO con minusculas: ";
	for (int i = 0; i < unTermino.longitud; i++){
		unNombre = unTermino.nombre;
		cout<<*((unTermino.nombre)+i);
	}
	cout<<endl;

	cout<<"CANTIDAD DE POSICIONES: "<<unTermino.cantPosiciones<<endl;
	cout<<"POSICIONES: ";
	for (int i = 0; i < unTermino.cantPosiciones; i++){
		cout<<*((unTermino.posiciones)+i)<<" ,";
	}
	cout<<endl;
	cout<<"LONGITUD: "<<unTermino.longitud<<endl;
	cout<<"DOCUMENTO: "<<unTermino.documento<<endl;
	cout<<endl;

	return 0;
}

int imprimirIDdocumentos(documento unDocumento){
	char *unNombre;
	cout<<"Nombre del documento: ";
	for (int i = 0; i < strlen(unDocumento.nombre); i++){
		unNombre = unDocumento.nombre;
		cout<<*((unDocumento.nombre)+i);
	}
	cout<<endl;
	cout<<"ID del doc: "<<unDocumento.id<<endl;
	cout<<endl;

}

int contarDocumentosDeDirectorio(char *unDirectorio,int *cantDocs){

	DIR *dir;
	struct dirent *directorio;

	dir = opendir (unDirectorio);
	if (dir == NULL) cout<<"No se pudo abrir el directorio"<<endl;

	while ((directorio = readdir (dir)) != NULL ) {
		if(directorio->d_type & DT_REG){
			(*cantDocs) ++;

		}
	}
	closedir (dir);
	return 0;
}


int leerDirectorio(char *unDirectorio, documento *listaDocumentos, int *cantDocs, int *cantTerminos){

	/*esta funcion ya le asigna a listaDocumentos el nombre y directorio completo de cada documento*/

	DIR *dir;
	FILE *unArchivo;
	struct dirent *directorio;
	int i=0;
	int id = 1;
	char *nombreCompleto;

	dir = opendir (unDirectorio);
	if (dir == NULL) cout<<"No se pudo abrir el directorio"<<endl;

	while ((directorio = readdir (dir)) != NULL ) {
		if(directorio->d_type & DT_REG){
			strcpy((*(listaDocumentos+i)).directorio, unDirectorio);
			strcat((*(listaDocumentos+i)).directorio, (const char*)(directorio->d_name));
			(*(listaDocumentos+i)).nombre = directorio->d_name;
			(*(listaDocumentos+i)).id = id;

			unArchivo = AbrirArchivo((*(listaDocumentos+i)).directorio);
			*cantTerminos = *cantTerminos + contarTerminos(unArchivo);
			i++;
			id++;
			fclose(unArchivo);
		}
	}

	closedir (dir);
	return 0;
	}



int leerArchivosDeDirectorio(termino *terminos, documento *listaDocumentos, int *cantDocs){

	FILE *unArchivo;
	int *pos;
	pos = (int*)malloc(sizeof(int));
	*pos = 0;

	for ( int i = 0; i <*cantDocs; i++){
		cout<<"un directorio para abrir: "<<(*(listaDocumentos+i)).directorio<<endl;

		unArchivo = AbrirArchivo((*(listaDocumentos+i)).directorio);
		leerArchivo(unArchivo, terminos, (*(listaDocumentos + i)).id , pos);
		fclose(unArchivo);
	}

	return 0;
	}

//
//ORDENAMIENTO MERGE SORT

//
// PARA COMPARAR LOS TERMINOS:
//	strncmp(&(*(terminos+i)->nombre),&(*(terminos+j)->nombre), longMin)
//
void mezclar(termino *vector1, int n1, termino *vector2, int n2, termino *lexico){
    int x1=0, x2=0, x3=0, longMin;

    while (x1<n1 && x2<n2) {

    	if ( (*(vector1 + x1)).longitud < (*(vector2 + x1)).longitud) longMin = (*(vector1 + x1)).longitud;
    	else longMin = (*(vector2 + x1)).longitud;

        if (strcmp(&(*(vector1+x1)->nombre),&(*(vector2+x2)->nombre)) < 0) {
            *(lexico+x3) = *(vector1+x1);
            x1++;
        } else {
            *(lexico+x3) = *(vector2+x2);
            x2++;
        }
        x3++;
    }
    while (x1<n1) {
        *(lexico+x3) = *(vector1+x1);
        x1++;
        x3++;
    }
    while (x2<n2) {
        *(lexico+x3) = *(vector2+x2);
        x2++;
        x3++;
    }
}

void mergeSort(termino *lexico, int n){
    termino *vector1, *vector2;
    int n1, n2,x,y;
    if (n>1){
        if (n%2 == 0)
            n1=n2=(int) n / 2;
        else{
            n1=(int) n / 2;
            n2=n1+1;
        }
        vector1=(termino*) malloc(sizeof(termino)*n1);
        vector2=(termino*) malloc(sizeof(termino)*n2);
        for(x=0;x<n1;x++)
            *(vector1+x) = *(lexico+x);
        for(y=0;y<n2;y++){
            *(vector2 + y)= *(lexico + x);
            x++;
        }
        mergeSort(vector1, n1);
        mergeSort(vector2, n2);

        mezclar(vector1, n1, vector2, n2, lexico);
        free(vector1);
        free(vector2);
    }

}
//
//	FINAL DEL MERGE SORT
//

//
//	A PARTIR DE ACA HAY QUE HACER PRUEBAS!!!
//
int guardarPosicion(int valor, int *posiciones, int tamanio){

	//almacena un numero en la lista de posiciones solo si ese numero no esta en la lista.
	//ya tiene que estar reservado el espacio en memoria para almacenar el nuevo valor.
	int existe = 0;

	for (int i = 0; i < tamanio; i ++){
		if (valor == *(posiciones+i)) existe = 1;
	}
	if (existe == 0){
		*(posiciones+tamanio-1) = valor;
	}
	return 0;
}


int guardarTerminoEnLexicoAgrupado(termino unTermino, terminoAgrupado *nuevoLexico, int *tamanio){

	int existe = 0;
	for (int i = 0; i < *tamanio; i++){
		if (strcmp((*(nuevoLexico+i)).nombre,unTermino.nombre) == 0 && (*(nuevoLexico+i)).documento == unTermino.documento){
			guardarPosicion(unTermino.posicion, (*(nuevoLexico + i)).posiciones, (*(nuevoLexico + i)).cantPosiciones);
			(*(nuevoLexico + i)).cantPosiciones = (*(nuevoLexico + i)).cantPosiciones +1;
			existe = 1;
		}
	}
	if (existe == 0){	//No existe!
		for (int j = 0; j < unTermino.longitud; j++){
			*(((*(nuevoLexico + *tamanio)).nombre)+j) = *((unTermino.nombre)+j);
		}
		(*(nuevoLexico + *tamanio)).documento = unTermino.documento;
		(*(nuevoLexico + *tamanio)).longitud = unTermino.longitud;
		(*(nuevoLexico + *tamanio)).cantPosiciones = 1;
		//*((*(nuevoLexico + tamanio)).posiciones) = unTermino.posicion;
		guardarPosicion(unTermino.posicion, (*(nuevoLexico + *tamanio)).posiciones, (*(nuevoLexico + *tamanio)).cantPosiciones);
		(*tamanio) ++;
	}

	return 0;
}


int agruparPalabrasPorDocumento(termino *lexico, terminoAgrupado *nuevoLexico, int totalTerminos, int *tamanioLexicoAgrupado){


	for (int i = 0; i < totalTerminos; i++ ){
		guardarTerminoEnLexicoAgrupado(*(lexico + i), nuevoLexico, tamanioLexicoAgrupado);
	}
	return 0;
}

